﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Timers;
using CalcSharp.Core;
using CalcSharp.Core.Containers;
using CalcSharp.Core.Plugin;
using InternetTime;


namespace plug_date_ex
{
    public class DateCMD : ICMDPlugin
    {

        private IPluginHost host;
        private SNTPClient inetclient;
        private Timer t;
        DateTime InetServerDate;
        const int updateinterval = 1000;

        /*
         * Constructor, but not defined as a normal constructor, because
         * when loading the plugin the normal constructor is called 2x
         * first to check that the object is an Iplugin and seccond time if it's Iplugin.
         */
        private void Construct()
        {
            this.inetclient = new SNTPClient(@"time.nist.gov");
            this.t = new Timer(updateinterval);
            this.t.Enabled = false;
            this.InetServerDate = new DateTime(2009, 1, 6);
            this.t.Elapsed += new ElapsedEventHandler(t_Elapsed);
        }

        void t_Elapsed(object sender, ElapsedEventArgs e)
        {
            this.InetServerDate = this.InetServerDate.AddMilliseconds(updateinterval);
        }

        /* plugin main code. This function is called when 
         * you type it's name to the console.
         * must return a Tresult vallue.
         * double.NaN value is not displayed in the console.
         */
        public Tresult Run(ArrayList parameters)
        {
            string param;
            Tresult res = new Tresult();
            int minutes = 0;
            if (parameters.Count > 0)
            {
                param = (parameters[0] as string).ToUpper();
                if (param == "YEAR") res.floatingpt = DateTime.Now.Year;
                else if (param == "MONTH") res.floatingpt = DateTime.Now.Month;
                else if (param == "DAY") res.floatingpt = DateTime.Now.Day;
                else if (param == "HOUR") res.floatingpt = DateTime.Now.Hour;
                else if (param == "MINUTE") res.floatingpt = DateTime.Now.Minute;
                else if (param == "SECOND") res.floatingpt = DateTime.Now.Second;
                else if (param == "DAYOFWEEK") res.floatingpt = (int)DateTime.Now.DayOfWeek;
                else if (param == "DAYOFYEAR") res.floatingpt = DateTime.Now.DayOfYear;
                else if (param == "DAYSINMONTH") res.floatingpt = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month);
                else if (param == "SECONDSELAPSED")
                {
                    minutes = (DateTime.Now.Hour * 60) + DateTime.Now.Minute;
                    res.floatingpt = minutes * 60 + DateTime.Now.Second;
                }
                else if (param == "INETTIME")
                {
                    DateTime UTC1 = DateTime.UtcNow.AddHours(1);
                    minutes = (UTC1.Hour * 60) + UTC1.Minute;
                    res.floatingpt = minutes * 60 + UTC1.Second;
                    res.floatingpt /= 86.4;
                    return res;
                }
                else if (param == "GETNETTIME")
                {
                    this.inetclient.Connect(false);
                    this.InetServerDate = this.inetclient.TransmitTimestamp;
                    this.InetServerDate.AddMilliseconds(this.inetclient.RoundTripDelay);
                    this.t.Enabled = true;
                    host.TextColor = ConsoleTextColor.TextOK;
                    host.writeln(" NTP Date request complete from: time.nist.gov");
                    host.writeln(" NTP Date and time: " + this.InetServerDate.ToString());
                    host.TextColor = ConsoleTextColor.NormalText;
                    res.floatingpt = double.NaN;
                }
                else if (param == "NETTIMEOFFSET")
                {
                    if (this.t.Enabled == false) host.writeln("Firs please get internet time using the DATETIME_EX GETNETTIME command");
                    else
                    {
                        TimeSpan diff = this.InetServerDate - DateTime.Now;
                        host.writeln(" NTP DateTime and Local time difference: " + diff.ToString());
                        if (diff.Days > 0) res.floatingpt = diff.Days;
                        else if (diff.Hours > 0) res.floatingpt = diff.Hours;
                        else if (diff.Minutes > 0) res.floatingpt = diff.Minutes;
                        else res.floatingpt = diff.Seconds;
                    }
                }
                else if (param == "NETSYNC")
                {
                    this.inetclient.Connect(true);
                    host.TextColor = ConsoleTextColor.TextOK;
                    host.writeln(" NTP Date sync request complete from: time.nist.gov");
                    host.writeln(" Curent Date & Time: " + DateTime.Now.ToString());
                    host.TextColor = ConsoleTextColor.NormalText;
                }
                else if (param == "UNIXTIME")
                {
                    DateTime unixstart = new DateTime(1970, 1, 1, 0, 0, 0);
                    TimeSpan utime = DateTime.UtcNow - unixstart;
                    res.floatingpt = utime.TotalSeconds;
                }
                else if (param == "UNIX2DATE")
                {
                    DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0);
                    double unix = Convert.ToDouble(parameters[1]);
                    dt = dt.AddSeconds(unix);
                    host.TextColor = ConsoleTextColor.TextOK;
                    host.writeln(" " + dt.ToString());
                    host.TextColor = ConsoleTextColor.NormalText;
                }
                else if (param == "DATE2UNIX")
                {
                    DateTime t;
                    DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0);
                    DateTime.TryParse(Convert.ToString(parameters[1]), out t);
                    TimeSpan ts = t - dt;
                    res.floatingpt = ts.TotalSeconds;
                }
                else if (param == "DIFF")
                {
                    DateTime d1, d2;
                    DateTime.TryParse(Convert.ToString(parameters[1]), out d1);
                    DateTime.TryParse(Convert.ToString(parameters[2]), out d2);
                    TimeSpan ts = d1 - d2;
                    res.floatingpt = Math.Abs(ts.TotalSeconds);
                }
                else if (param == "SECS2TIME")
                {
                    DateTime date = new DateTime();
                    date = date.AddSeconds(Convert.ToDouble(parameters[1]));
                    host.TextColor = ConsoleTextColor.TextOK;
                    host.writeln(" " + date.ToString());
                    host.TextColor = ConsoleTextColor.NormalText;

                }
                else throw new CSException("Unknown Command:" + param);
            }
            return res;
        }

        public Dictionary<string, string> autocomplete
        {
            get
            {
                Dictionary<string, string> elements = new Dictionary<string, string>();
                elements.Add("Date commands", "YEAR;MONTH;DAY;HOUR;MINUTE;SECOND;DAYOFWEEK;DAYOFYEAR;DAYSINMONTH;SECONDSELAPSED;INETTIME;GETNETTIME;NETTIMEOFFSET;UNIXTIME;UNIX2DATE;DATE2UNIX;DIFF;SECS2TIME;NETSYNC");
                return elements;
            }
        }

        public string Name
        {
            //should be given like this:
            get { return "DATETIME_EX"; }
        }

        public string Help
        {
            /*
             * The easiest way to make a help document is
             * to make a html and add it as a resource to the
             * project and return it as a vallue.
             */
            get { return Properties.Resources.help; }
        }

        // Must be implemented like this! If you change this
        // property the plugin might not work. 
        public IPluginHost Host
        {
            get
            {
                return host;
            }
            set
            {
                host = value;
                // constructor is called here, because this only runs down when attaching the plugin
                // to the prorgram.
                this.Construct();
                host.Register(this);
            }
        }
    }
}
